package com.smartcommunity.service.dataImport;

import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Sets;
import com.smartcommunity.lis.BimgClientPool;
import com.smartcommunity.lis.BimgException;
import com.smartcommunity.base.bean.ExceptionCode;
import com.smartcommunity.base.common.CacheMap;
import com.smartcommunity.base.common.DataImport;
import com.smartcommunity.bean.constant.Constant;
import com.smartcommunity.bean.entity.ImportErrorMsg;
import com.smartcommunity.bean.entity.ImportField;
import com.smartcommunity.controller.DataImportBase;
import com.smartcommunity.dao.people.PeopleDao;
import com.smartcommunity.dao.tag.TagDao;
import com.smartcommunity.dao.village.HouseDao;
import com.smartcommunity.entity.people.People;
import com.smartcommunity.entity.people.RealPeopleHouse;
import com.smartcommunity.entity.tag.Tag;
import com.smartcommunity.exception.BusinessException;
import com.smartcommunity.log.interceptor.Log;
import com.smartcommunity.service.dataImport.model.PeopleExportModel;
import com.smartcommunity.service.people.PeopleService;
import com.smartcommunity.service.village.VillageService;
import com.smartcommunity.utils.HttpClientUtil;
import com.smartcommunity.utils.IDCardUtil;
import com.smartcommunity.utils.RegExUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.*;

@Component("people")
@Slf4j
public class PeopleImport extends DataImportBase implements DataImport {

    private final PeopleDao peopleDao;

    @Autowired
    public PeopleImport(PeopleDao peopleDao) {
        this.peopleDao = peopleDao;
    }

    @Autowired
    private HouseDao houseDao;

    @Autowired
    private VillageService villageService;

    @Autowired
    private TagDao tagDao;
    
    @Autowired
    private PeopleService peopleService;

    @Autowired
    BimgClientPool lis;

    /**
     * 模板类型
     */
    private String type = "实有人口";

    /**
     * 内容标题
     */
    private  String[] headerTitle = new String[]{
            "人员类型",
            "证件类型",
            "证件号码",
            "姓名",
            "性别",
            "民族",
            "楼栋编号",
            "单元号",
            "房间编号",
            "手机号码",
            "户籍地址",
            "人口标签",
            "人口图片"};

    /**
     * 错误信息
     */
    private  String[] headerErrorMsg = new String[]{
            "为空、或类型错误",
            "为空、或类型错误",
            "为空、或格式错误",
            "为空、或长度超过100位",
            "格式错误",
            "没有此民族",
            "当前小区没有此编号",
            "当前小区没有此编号",
            "当前小区没有此编号",
            "不是数字、长度超过20位",
            "长度超过100位",
            "",
            ""};

    /**
     * key taskId,value progress
     */
    final int cacheSize = 100000;
    Map<String, Integer> progressTag = new LinkedHashMap<String, Integer>((int) Math.ceil(cacheSize / 0.75f) + 1, 0.75f, true) {
        @Override
        protected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) {
            return size() > cacheSize;
        }
    };

    /**
     * 导入实有人员信息
     *
     * @param list        excel数据列表
     * @param villageCode 小区编码
     */
    @Override
    @Transactional
    @Log(info = "实有人口模板导入")
    public String importData(List list, String villageCode,String fileName, String taskId,HttpServletResponse response) throws  IllegalArgumentException, BusinessException {
        progressTag.put(taskId, 10);
        // 设置小区编码（必填）
        if (StringUtils.isBlank(villageCode)) {
            throw new IllegalArgumentException("小区编码为空！");
        }

        //初始化导入模板信息
        ImportErrorMsg msg = getFiledInfo(type,headerTitle,headerErrorMsg);

        //字段校验信息
        List<ImportField> fieldList = msg.getFieldList();

        //根据小区编号获取所有的楼栋编号 单元号和房屋编号
        Map<String, Map<String, List<String>>> allHouses = villageService.getAllHousesByVillageCode(villageCode);

        //获取所有标签信息
        Map<String,Tag> tagMap = new HashMap<>();
        List<Tag> tags = tagDao.getTagList(null);
        for(Tag tag :tags){
            tagMap.put(tag.getTagName(),tag);
        }

        List<Object[]> dataList = (List<Object[]>) list;
        //存储错误信息
        List<PeopleExportModel> dataListCopy = new ArrayList<>();
        List<People> peopleList = new ArrayList<>();
        List<RealPeopleHouse> delPeopleHouseList = new ArrayList<>();
        List<RealPeopleHouse> peopleHouseList = new ArrayList<>();
        int size = dataList.size();
        int errorCount = 0;

        for (int i = 0; i < size; i++) {
            boolean isError = false;
            Object[] objects = dataList.get(i);
            int currentRow = Constant.START_ROW + i;

            int fixColumnLen = 12;
            if(objects.length < fixColumnLen){
                throw new BusinessException("模板文件列数不对，请检查模板文件！");
            }

            // 空行校验，跳过空行
            List<String> oneLine = Arrays.stream(objects)
                    .map(o -> StrUtil.trim(Objects.toString(o, EMPTY)))
                    .collect(Collectors.toList());
            if(oneLine.stream().allMatch(StrUtil::isEmpty)){
                log.info("第{}行全为空，跳过该行",currentRow);
                continue;
            }

            People people = new People();
            RealPeopleHouse peopleHouse = new RealPeopleHouse();

            people.setVillageCode(villageCode);
            peopleHouse.setVillageCode(villageCode);

            StringBuffer errorMessages = new StringBuffer();
            // 设置实有人口类别（必填）
            String peopleType = String.valueOf(objects[0]);
            if (StringUtils.isBlank(peopleType) || CacheMap.PEOPLE_TYPE_NAME_MAP.get(peopleType)==null) {
                //添加错误的行数
                String errorMsg = appendErrorMsg(fieldList.get(0).getTitle(), peopleType, fieldList.get(0).getErrorMsg());
                errorMessages.append(errorMsg);
                isError = true;
            }else{
                people.setPeopleType(CacheMap.PEOPLE_TYPE_NAME_MAP.get(peopleType));
            }

            // 设置证件类型（必填）
            String credentialType = String.valueOf(objects[1]);
            if (StringUtils.isBlank(credentialType) || CacheMap.CREDENTIAL_TYPE_NAME_MAP.get(credentialType)==null) {
                //添加错误的行数
                String errorMsg = appendErrorMsg(fieldList.get(1).getTitle(), credentialType, fieldList.get(1).getErrorMsg());
                errorMessages.append(errorMsg);
                isError = true;
            }else{
                people.setCredentialType(String.valueOf(CacheMap.CREDENTIAL_TYPE_NAME_MAP.get(credentialType)));
                people.setCredentialTypeCN(credentialType);
                peopleHouse.setCredentialType(String.valueOf(CacheMap.CREDENTIAL_TYPE_NAME_MAP.get(credentialType)));
            }

            // 设置证件号（必填）
            String credentialNo = String.valueOf(objects[2]);
            if (StringUtils.isBlank(credentialNo)) {
                String errorMsg = appendErrorMsg(fieldList.get(2).getTitle(), credentialNo, fieldList.get(2).getErrorMsg());
                errorMessages.append(errorMsg);
                isError = true;
            }else{
                if(length(credentialNo)>18){
                    String errorMsg = appendErrorMsg(fieldList.get(2).getTitle(), credentialNo, fieldList.get(2).getErrorMsg());
                    errorMessages.append(errorMsg);
                    isError = true;
                }

                //判断是否是居民身份证
                if (Constant.IDCARD_NAME_VALUE.equals(credentialType)) {
                    if (!RegExUtils.isIdCardNo(credentialNo)) {
                        String errorMsg = appendErrorMsg(fieldList.get(2).getTitle(), credentialNo, fieldList.get(2).getErrorMsg());
                        errorMessages.append(errorMsg);
                        isError = true;
                    }

                    // 设置出生日期（必填）
                    StringBuffer birthDate = new StringBuffer();
                    if (credentialNo.length() == 15 ) {
                        //补齐年份 19
                        birthDate.append(19).append(credentialNo.substring(6,8)).append("-")
                                .append(credentialNo.substring(8,10)).append("-").append(credentialNo.substring(10,12));
                    }else  if (credentialNo.length() == 18) {
                        birthDate.append(credentialNo.substring(6,10)).append("-")
                                .append(credentialNo.substring(10,12)).append("-").append(credentialNo.substring(12,14));
                    }
                    try {
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd");
                        sdf.parse(birthDate.toString());
                        people.setBirthDate(birthDate.toString());
                    } catch (ParseException ie) {
                        people.setBirthDate("");
                    }
                }
            }
            people.setCredentialNo(credentialNo);
            peopleHouse.setCredentialNo(credentialNo);


            // 设置姓名（必填）
            String peopleName = String.valueOf(objects[3]);
            if (StringUtils.isBlank(peopleName) || length(peopleName)>100) {
                String errorMsg = appendErrorMsg(fieldList.get(3).getTitle(), peopleName, fieldList.get(3).getErrorMsg());
                errorMessages.append(errorMsg);
                isError = true;
            }
            people.setPeopleName(peopleName);

            // 设置性别（选填）
            String gender = String.valueOf(objects[4]);
            if(StringUtils.isNotBlank(gender)){
                if(!CacheMap.GENDER_NAME_MAP.containsKey(gender)){
                    String errorMsg = appendErrorMsg(fieldList.get(4).getTitle(), peopleName, fieldList.get(4).getErrorMsg());
                    errorMessages.append(errorMsg);
                    isError = true;
                }else {
                    people.setGender(gender);
                    people.setGenderCode(CacheMap.GENDER_NAME_MAP.get(gender));
                }
            }else{
                //判断证件号码是否为身份证
                people.setGender("未知");
                people.setGenderCode(0);
                if (RegExUtils.isIdCardNo(credentialNo)) {
                    Integer genderInfo = IDCardUtil.getSex(credentialNo);
                    if(genderInfo!=null){
                        gender = genderInfo==0?"女":"男";
                        people.setGender(gender);
                        people.setGenderCode(CacheMap.GENDER_NAME_MAP.get(gender));
                    }
                }
            }

            // 设置民族 (选填)
            String nation = String.valueOf(objects[5]);
            if (StringUtils.isNotBlank(nation)) {
                if(CacheMap.NATION_NAME_MAP.get(nation)==null){
                    String errorMsg = appendErrorMsg(fieldList.get(5).getTitle(), nation, fieldList.get(5).getErrorMsg());
                    errorMessages.append(errorMsg);
                    isError = true;
                }else {
                	people.setNation(CacheMap.NATION_NAME_MAP.get(nation).toString());
                }
            }

            // 设置楼栋（选填）
            String buildingNo = String.valueOf(objects[6]);
            if (StringUtils.isNotBlank(buildingNo)) {
                //如果有填，判断楼栋号是否存在
                if (!allHouses.containsKey(buildingNo)) {
                    //添加错误的行数
                    String errorMsg = appendErrorMsg(fieldList.get(6).getTitle(), buildingNo, fieldList.get(6).getErrorMsg());
                    errorMessages.append(errorMsg);
                    isError = true;
                }else {
                	peopleHouse.setBuildingNo(buildingNo);
                }
            }
            
            //设置单元号(选填)
            String unitNo = String.valueOf(objects[7]);
            if(StringUtils.isNotBlank(unitNo) && StringUtils.isNotBlank(peopleHouse.getBuildingNo())) {
            	//如果有填，判断单元号是否存在
            	if(!allHouses.get(peopleHouse.getBuildingNo()).containsKey(unitNo)) {
            		//添加错误的行数
                    String errorMsg = appendErrorMsg(fieldList.get(7).getTitle(), unitNo, fieldList.get(7).getErrorMsg());
                    errorMessages.append(errorMsg);
                    isError = true;
            	}else {
            		peopleHouse.setUnitNo(unitNo);
            	}
            }

            // 设置房间号（选填）
            String houseNo = String.valueOf(objects[8]);
            if (StringUtils.isNotBlank(houseNo) && StringUtils.isNotBlank(peopleHouse.getBuildingNo()) && StringUtils.isNotBlank(peopleHouse.getUnitNo())) {
            	List<String> houseNos = allHouses.get(peopleHouse.getBuildingNo()).get(peopleHouse.getUnitNo());
                //如果有填，判断房间号是否存在
                if (!houseNos.contains(houseNo)) {
                    //添加错误的行数
                    String errorMsg = appendErrorMsg(fieldList.get(8).getTitle(), houseNo, fieldList.get(8).getErrorMsg());
                    errorMessages.append(errorMsg);
                    isError = true;
                }else {
                	peopleHouse.setHouseNo(houseNo);
                }
            }

            // 手机号码（可选）
            String phoneNo = String.valueOf(objects[9]);
            if (StringUtils.isNotBlank(phoneNo)) {
                if (length(phoneNo)>20 || !RegExUtils.isNumeric(phoneNo)) {
                    //添加错误的行数
                    String errorMsg = appendErrorMsg(fieldList.get(9).getTitle(), phoneNo, fieldList.get(9).getErrorMsg());
                    errorMessages.append(errorMsg);
                    isError = true;
                }
                people.setPhoneNo(phoneNo);
            }

            // 设置户籍地址（可选）
            String domicileAddress = String.valueOf(objects[10]);
            if (StringUtils.isNotBlank(domicileAddress)) {
                if(length(domicileAddress)>100){
                    String errorMsg = appendErrorMsg(fieldList.get(10).getTitle(), domicileAddress, fieldList.get(10).getErrorMsg());
                    errorMessages.append(errorMsg);
                    isError = true;
                }
                people.setDomicileAddress(domicileAddress);
            }

            // 标签，中文，逗号分隔(选填)
            String tagInput =  String.valueOf(objects[11]);
            if (isNotBlank(tagInput)) {
                StringBuffer tagIds = new StringBuffer();
                Set<String> tagNames = Sets.newHashSet(SpTagName.splitToList(tagInput));
                for(String tagName :tagNames){
                    if(tagMap.containsKey(tagName)){
                        Integer tagId = tagMap.get(tagName).getId();
                        tagIds.append(tagId).append(",");
                    }
                }
                if(length(tagIds.toString())>0){
                    people.setLabel(tagIds.substring(0,tagIds.length()-1));
                }
            }

            // 人口照片地址（可选）
            String IdCardPic = String.valueOf(objects[12]);
            if (StringUtils.isNotBlank(IdCardPic)) {
                people.setIdCardPic(IdCardPic);
            }

            //判断当前行是否有错误
            if(isError){
                errorCount++;
                PeopleExportModel exportModel=new PeopleExportModel();
                exportModel.setPeopleType(String.valueOf(objects[0]));
                exportModel.setCredentialType(String.valueOf(objects[1]));
                exportModel.setCredentialNo(String.valueOf(objects[2]));
                exportModel.setPeopleName(String.valueOf(objects[3]));
                exportModel.setGender(String.valueOf(objects[4]));
                exportModel.setNation(String.valueOf(objects[5]));
                exportModel.setBuildingNo(String.valueOf(objects[6]));
                exportModel.setUnitNo(String.valueOf(objects[7]));
                exportModel.setHouseNo(String.valueOf(objects[8]));
                exportModel.setPhoneNo(String.valueOf(objects[9]));
                exportModel.setDomicileAddress(String.valueOf(objects[10]));
                exportModel.setPeopleTag(String.valueOf(objects[11]));
                exportModel.setFacePic(String.valueOf(objects[12]));
                exportModel.setErrorMsg(errorMessages.toString());
                dataListCopy.add(exportModel);
            }else{
                // 加入用户列表
                peopleList.add(people);
                // 加入人房关系
                peopleHouseList.add(peopleHouse);
                // 要删掉此人分配楼栋房屋的关联数据
                delPeopleHouseList.add(peopleHouse);
            }
        }


        // 入库人员信息
        try {
            if(CollectionUtils.isNotEmpty(peopleList) &&
                    CollectionUtils.isNotEmpty(peopleHouseList) &&
                    CollectionUtils.isNotEmpty(delPeopleHouseList)){
                // 删除人房关系
                log.info("开始删除人房关系");
                houseDao.batchDeletePeopleHouse(delPeopleHouseList);
                progressTag.put(taskId,15);
                // 人员信息
                log.info("开始导入人口信息");
                peopleDao.insertPeoples(peopleList);
                progressTag.put(taskId,60);
                // 人房关系
                log.info("开始导入人房关系");
                houseDao.insertPeopleHouse(peopleHouseList);
                progressTag.put(taskId,70);
                // 人员照片
                log.info("开始导入人口照片");
                importPeoplePic(peopleList);
                progressTag.put(taskId,80);
                //ES实口入库
                peopleService.syncDataToEs(villageCode, null);
            }
            //正常的数据需要导入进去，错误的数据返回到Excel
            if (errorCount>0) {
                String errorFileName = exportExcelToLocal(taskId,fileName,headerTitle,dataListCopy);
                progressTag.put(taskId,100);
                return errorFileName;
            }
        } catch (BusinessException e) {
            log.error("实有人口导入失败，入库ES异常！", e);
            throw new BusinessException(ExceptionCode.PEOPLE_IMPORT_EXCEPTION_CODE, "实有人口导入失败，入库ES异常！");
        } catch (Exception e) {
            log.error("实有人口导入失败，保存数据库异常！", e);
            throw new BusinessException(ExceptionCode.PEOPLE_SQL_EXCEPTION_CODE, "实有人口导入失败，保存数据库异常！");
        }
        log.info("实有人口信息导入完成");
        progressTag.put(taskId,100);
        return "";
    }

    @Override
    public int getImportDataProgress(String taskId) {
        return progressTag.get(taskId) == null ? 0 : progressTag.get(taskId);
    }


    public void importPeoplePic(List<People> peopleList) throws BimgException {
        List<Map<String, Object>> pathList = new ArrayList<>();
        Map<String, Object> pathMap;
        for(People people : peopleList){
            if(StringUtils.isBlank(people.getIdCardPic())){
                continue;
            }
            pathMap = new HashMap<>(2);

            // 设置照片的标识
            pathMap.put("idNo", people.getCredentialNo());

            //获取人员图片
            byte[] bytes = HttpClientUtil.getFileByte(people.getIdCardPic(),"");
            if(bytes==null){
                log.info(people.getCredentialNo()+"download img is null");
                continue;
            }
            // 保存到LIS
            String path = lis.uploadImageForever(bytes);
            // 设置图片保存地址
            pathMap.put("picPath", path);
            // 加入入库列表
            pathList.add(pathMap);
        }

        // 图片信息入库
        if(pathList.size()>0){
            peopleDao.updatePic(pathList);
        }
    }
}
